home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1990 Free Software Foundation, Inc.
-
- This file is part of Oleo, the GNU Spreadsheet.
-
- Oleo is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- Oleo is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Oleo; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "funcdef.h"
-
- #include <stdio.h>
-
- #define obstack_chunk_alloc ck_malloc
- #define obstack_chunk_free free
- #include "obstack.h"
-
- #include "sysdef.h"
-
- #include "global.h"
- #include "node.h"
- #include "eval.h"
-
- /* should be struct var *, but we're cheating */
- extern void add_var_ref EXT1(void *);
-
- static void add_backpatch EXT2(unsigned, unsigned);
-
- struct backpatch {
- unsigned from,to;
- };
-
- static struct backpatch *patches;
- static int patches_allocated;
- static int patches_used;
- static VOIDSTAR fn_stack;
- static VOIDSTAR str_stack;
-
- struct obstack tmp_mem;
- VOIDSTAR tmp_mem_start;
-
- extern double atan2 EXT2(double,double);
- extern double hypot EXT2(double,double);
- extern double floor EXT1(double);
- extern double cos EXT1(double);
- extern double to_int EXT1(double);
- extern double dtr EXT1(double);
- extern double rtd EXT1(double);
- extern double exp EXT1(double);
- extern double log10 EXT1(double);
- extern double sin EXT1(double);
- extern double sqrt EXT1(double);
- extern double tan EXT1(double);
-
- extern double acos EXT1(double);
- extern double asin EXT1(double);
- extern double atan EXT1(double);
- extern double ceil EXT1(double);
-
- #define V (void(*)())
-
- /* These have to go in some file or other, so it is stuck in here (for now).
- */
- struct function the_funs[] = {
- { 0, X_A0, "", 0, "<END>" },
- { 0, X_A0, "", 0, "<DUMMY1>" },
-
- { C_IF|R|INF(1), X_A1|X_J, "D", 0, "?" },
- { C_IF|R|INF(1), X_A1|X_JL, "D", 0, "?" },
- { C_IF, X_A1|X_J, "D", 0, "if" },
- { C_IF, X_A1|X_JL, "D", 0, "if" },
- { C_ANDOR, X_A1|X_J, "D", 0, "and" },
- /* { C_ANDOR|L|INF(3), X_A1, "DD", 0, "&" }, */
- { C_ANDOR, X_A1|X_JL, "D", 0, "and" },
- /* { C_ANDOR|L|INF(3), X_A1, "DD", 0, "&" }, */
- { C_ANDOR, X_A1|X_J, "D", 0, "or" },
- /* { C_ANDOR|L|INF(2), X_A1, "DD", 0, "|" }, */
- { C_ANDOR, X_A1|X_JL, "D", 0, "or" },
- /* { C_ANDOR|L|INF(2), X_A1, "DD", 0, "|" }, */
- { C_STR, X_A0|X_J, "", 0, "\"%s\"" },
- { C_STR, X_A0|X_JL, "", 0, "\"%s\"" },
-
- #ifdef A0_REFS
- { C_CELL, X_A0, "", 0, "$%s$%u" },
- { C_CELL, X_A0, "", 0, "$%s%u" },
- { C_CELL, X_A0, "", 0, "%s$%u" },
- { C_CELL, X_A0, "", 0, "%s%u" },
- { C_RANGE, X_A0, "", 0, "$%s$%u:$%s$%u" },
- { C_RANGE, X_A0, "", 0, "$%s%u:$%s$%u" },
- { C_RANGE, X_A0, "", 0, "$%s$%u:$%s%u" },
- { C_RANGE, X_A0, "", 0, "$%s%u:$%s%u" },
- { C_RANGE, X_A0, "", 0, "%s$%u:$%s$%u" },
- { C_RANGE, X_A0, "", 0, "%s%u:$%s$%u" },
- { C_RANGE, X_A0, "", 0, "%s$%u:$%s%u" },
- { C_RANGE, X_A0, "", 0, "%s%u:$%s%u" },
- { C_RANGE, X_A0, "", 0, "$%s$%u:%s$%u" },
- { C_RANGE, X_A0, "", 0, "$%s%u:%s$%u" },
- { C_RANGE, X_A0, "", 0, "$%s$%u:%s%u" },
- { C_RANGE, X_A0, "", 0, "$%s%u:%s%u" },
- { C_RANGE, X_A0, "", 0, "%s$%u:%s$%u" },
- { C_RANGE, X_A0, "", 0, "%s%u:%s$%u" },
- { C_RANGE, X_A0, "", 0, "%s$%u:%s%u" },
- { C_RANGE, X_A0, "", 0, "%s%u:%s%u" },
- #else
- { C_CELL, X_A0, "", 0, "r%uc%u" },
- { C_CELL, X_A0, "", 0, "r[%+d]c%u" },
- { C_CELL, X_A0, "", 0, "r%uc[%+d]" },
- { C_CELL, X_A0, "", 0, "r[%+d]c[%+d]" },
- { C_RANGE, X_A0, "", 0, "r%u:%uc%u:%u" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:%uc%u:%u" },
- { C_RANGE, X_A0, "", 0, "r%u:[%+d]c%u:%u" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c%u:%u" },
- { C_RANGE, X_A0, "", 0, "r%u:%uc[%+d]:%u" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:%uc[%+d]:%u" },
- { C_RANGE, X_A0, "", 0, "r%u:[%+d]c[%+d]:%u" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c[%+d]:%u" },
- { C_RANGE, X_A0, "", 0, "r%u:%uc%u:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:%uc%u:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r%u:[%+d]c%u:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c%u:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r%u:%uc[%+d]:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:%uc[%+d]:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r%u:[%+d]c[%+d]:[%+d]" },
- { C_RANGE, X_A0, "", 0, "r[%+d]:[%+d]c[%+d]:[%+d]" },
- #endif
-
- { C_CONST, X_A0, "", 0, tname },
- { C_CONST, X_A0, "", 0, fname },
-
- { C_CONST, X_A0, "", 0, iname },
- { C_CONST, X_A0, "", 0, mname },
- { C_CONST, X_A0, "", 0, nname },
- { C_ERR, X_A0|X_J, "", 0, "%s" },
- { C_FLT, X_A0, "", 0, "%.15g" },
- { C_INT, X_A0, "", 0, "%ld" },
-
- { C_VAR, X_A0, "", 0, "%s" },
-
- { C_UNA, X_A1, "F", 0, "-" },
- { C_UNA, X_A1, "B", 0, "!" },
-
- { C_INF|L|INF(6), X_A2, "NN", 0, "-" },
- { C_INF|L|INF(7), X_A2, "NN", 0, "/" },
- { C_INF|L|INF(7), X_A2, "NN", 0, "%" },
- { C_INF|L|INF(7), X_A2, "NN", 0, "*" },
- { C_INF|L|INF(6), X_A2, "NN", 0, "+" },
- { C_INF|L|INF(2), X_A2, "SS", 0, "&" },
- { C_INF|N|INF(4), X_A2, "AA", 0, "=" },
- { C_INF|N|INF(5), X_A2, "AA", 0, ">=" },
- { C_INF|N|INF(5), X_A2, "AA", 0, ">" },
- { C_INF|N|INF(5), X_A2, "AA", 0, "<" },
- { C_INF|N|INF(5), X_A2, "AA", 0, "<=" },
- { C_INF|N|INF(4), X_A2, "AA", 0, "!=" },
- { C_INF|R|INF(8), X_A2, "FF", V pow, "^" },
-
- { C_FN0, X_A0, "", 0, "pi" },
- { C_FN0X, X_A0, "", 0, "row" },
- { C_FN0X, X_A0, "", 0, "col" },
- { C_FN0|C_T, X_A0, "", 0, "now" },
-
- { C_FN1, X_A1, "F", V fabs, "abs" },
- { C_FN1, X_A1, "F", V acos, "acos" },
- { C_FN1, X_A1, "F", V asin, "asin" },
- { C_FN1, X_A1, "F", V atan, "atan" },
- { C_FN1, X_A1, "F", V ceil, "ceil" },
- { C_FN1, X_A1, "F", V to_int, "int" },
- { C_FN1, X_A1, "F", V floor, "floor" },
- { C_FN1, X_A1, "F", V cos, "cos" },
- { C_FN1, X_A1, "F", V dtr, "dtr" },
- { C_FN1, X_A1, "F", V exp, "exp" },
- { C_FN1, X_A1, "F", V log, "log" },
- { C_FN1, X_A1, "F", V log10, "log10" },
- { C_FN1, X_A1, "F", V rtd, "rtd" },
- { C_FN1, X_A1, "F", V sin, "sin" },
- { C_FN1, X_A1, "F", V sqrt, "sqrt" },
- { C_FN1, X_A1, "F", V tan, "tan" },
- { C_FN1, X_A1, "I", 0, "ctime" },
- { C_FN1, X_A1, "A", 0, "negate" },
- { C_FN1, X_A1, "A", 0, "not" },
- { C_FN1, X_A1, "A", 0, "iserr" },
- { C_FN1, X_A1, "A", 0, "isnum" },
-
- { C_FN1|C_T, X_A1, "I", 0, "rnd" },
- { C_FN1, X_A1, "R", 0, "rows" },
- { C_FN1, X_A1, "R", 0, "cols" },
- { C_FN2, X_A2, "FF", V atan2, "atan2" },
- { C_FN2, X_A2, "FF", V hypot, "hypot" },
- { C_FN2, X_A2, "FI", 0, "fixed" },
- { C_FN2, X_A2, "AA", 0, "iferr" },
- { C_FN2, X_A2, "RI", 0, "index" },
- { C_FN3, X_A3, "RII", 0, "index" },
- { C_FNN, X_AN, "IAAA", 0, "oneof" },
-
- { C_FNN, X_AN, "SIIA", 0, "file" },
- { C_FNN, X_AN, "EEEE", 0, "sum" },
- { C_FNN, X_AN, "EEEE", 0, "prod" },
- { C_FNN, X_AN, "EEEE", 0, "avg" },
- { C_FNN, X_AN, "EEEE", 0, "std" },
- { C_FNN, X_AN, "EEEE", 0, "max" },
- { C_FNN, X_AN, "EEEE", 0, "min" },
- { C_FNN, X_AN, "EEEE", 0, "count" },
- { C_FNN, X_AN, "EEEE", 0, "var" },
-
- };
-
- #ifdef USE_DLD
- int n_usr_funs;
- struct function **usr_funs;
- int *usr_n_funs;
- #else
- int n_usr_funs = 3;
- extern struct function busi_funs[];
- extern struct function string_funs[];
- extern struct function cells_funs[];
-
- static struct function *__usr_funs[] = {
- busi_funs,
- string_funs,
- cells_funs,
- };
- static int __usr_n_funs[] = {
- 18, 11, 10
- };
-
- struct function **usr_funs = __usr_funs;
- int *usr_n_funs = __usr_n_funs;
- #endif
-
- /* ... A whole huge empty space, then ... */
- struct function skip_funs[] = {
- { C_SKIP, X_A0|X_J, "", 0, "<Skip %u>" },
- { C_SKIP, X_A0|X_JL, "", 0, "<SkipL %u>" },
- };
-
- /* The memory allocated here is used for several things, but byte_compile
- is a small file, so it might as well be here */
- void
- init_mem FUN0()
- {
- int n;
- extern VOIDSTAR hash_new();
-
- parse_hash=hash_new();
- hash_insert(parse_hash,the_funs[F_IF].fn_str,&the_funs[F_IF]);
- hash_insert(parse_hash,the_funs[AND].fn_str,&the_funs[AND]);
- hash_insert(parse_hash,the_funs[OR].fn_str,&the_funs[OR]);
- for(n=F_PI;n<USR1;n++)
- hash_insert(parse_hash,the_funs[n].fn_str,&the_funs[n]);
- #ifndef USE_DLD
- for(n=0;n<n_usr_funs;n++) {
- int nn;
-
- for(nn=0;usr_funs[n][nn].fn_str;nn++)
- hash_insert(parse_hash,usr_funs[n][nn].fn_str,&usr_funs[n][nn]);
- #ifdef TEST
- if(usr_n_funs[n]!=nn) {
- fprintf(stderr,"Usr_n_funs[%d]%d!=%d",n,usr_n_funs[n],nn);
- usr_n_funs[n]=nn;
-
- }
- #endif
- }
- #endif
- fn_stack=init_stack();
- str_stack=init_stack();
- obstack_begin(&tmp_mem,400);
- tmp_mem_start=obstack_alloc(&tmp_mem,0);
- }
-
- #ifdef USE_DLD
- void
- add_usr_funs FUN1(struct function *,new_funs)
- {
- int n;
-
- n_usr_funs++;
-
- usr_funs=usr_funs ? ck_realloc(usr_funs,n_usr_funs*sizeof(struct function *)) : ck_malloc(sizeof(struct function *));
-
- usr_n_funs = usr_n_funs ? ck_realloc(usr_n_funs,n_usr_funs*sizeof(int)) : ck_malloc(sizeof(int));
-
- usr_funs[n_usr_funs-1]=new_funs;
- for(n=0;new_funs[n].fn_str;n++)
- hash_insert(parse_hash,new_funs[n].fn_str,&new_funs[n]);
- usr_n_funs[n_usr_funs-1]=n;
- }
- #endif
-
- /* Stash away a backpatch for future editing. */
- static void
- add_backpatch FUN2(unsigned, from,unsigned, to)
- {
- if(!patches) {
- patches_allocated=5;
- patches=(struct backpatch *)ck_malloc(patches_allocated*sizeof(struct backpatch));
- patches_used=0;
- }
- if(patches_allocated==patches_used) {
- patches_allocated*=2;
-
- patches=(struct backpatch *)ck_realloc(patches,patches_allocated*sizeof(struct backpatch));
- }
- patches[patches_used].from=from;
- patches[patches_used].to=to;
- patches_used++;
- }
-
- static int
- cmp_patch FUN2(int,n1, int,n2)
- {
- int ret;
-
- ret=(patches[n1].from == patches[n2].from) ? patches[n1].to-patches[n2].to : patches[n1].from - patches[n2].from;
- return ret;
- }
-
- static void
- swp_patch FUN2(int,n1, int,n2)
- {
- struct backpatch tmp;
-
- tmp=patches[n1];
- patches[n1]=patches[n2];
- patches[n2]=tmp;
- }
-
- static void
- rot_patch FUN2(int,n1, int,n2)
- {
- struct backpatch tmp;
- tmp=patches[n2];
- while(n2>n1) {
- patches[n2]=patches[n2-1];
- --n2;
- }
- patches[n2]=tmp;
- }
-
-
- /* This takes an ascii string and returns a pointer to the byte-compiled
- result. It calls yyparse() to do the actual parsing. This is complicated
- only because yyparse returns a parse tree which needs to be turned into
- postfix compiled bytes. This is further complicated by the presence of
- forward branches in the byte-compiled code. That's what the backpatch
- stuff is for.
-
- It'd be nice if oneof() could compile into
- arg1
- ONEOF n_possibilities
- JUMP poss1
- JUMP poss2
- JUMP poss3
- ...
- JUMP error
- {poss 1}
- JUMP end
- {poss 2}
- JUMP end
- ...
- end: {rest of expression}
- instead of the simplistic (and slow-to-execute) version currently used
-
- It'd also be nice if byte-compiled expressions could have *BIG*
- subexpressions, instead of silently failing as they do now. Error checking
- and a way to encode longer branches would be a *good* idea.
- */
- unsigned char *
- parse_and_compile FUN1(char *,string)
- {
- struct node *new_node;
- struct node *node;
- struct function *f;
- unsigned char *ret;
- int n;
- unsigned buf_siz;
- int need_relax;
- int byte;
-
- extern int yyparse EXT0();
- extern char *instr;
- extern int parse_error;
- extern struct node *parse_return;
-
- instr=string;
- parse_error=0;
- patches_used=0;
- if(yyparse() || parse_error) {
- ret=ck_malloc(strlen(string)+5);
- ret[0]=CONST_ERR;
- ret[1]=2;
- ret[2]=parse_error;
- ret[3]=ENDCOMP;
- strcpy((char *)&ret[4],string);
- (void)obstack_free(&tmp_mem,tmp_mem_start);
- return ret;
- }
-
- node=parse_return;
- if(!node)
- return 0;
-
- loop:
- if(node->comp_value<USR1) {
- f= &the_funs[node->comp_value];
- byte=node->comp_value;
- } else if(node->comp_value<SKIP) {
- n=node->sub_value;
- f= &usr_funs[node->comp_value-USR1][n];
- /* Wait until this has no subrs left. . . */
- if(!node->n_x.v_subs[0] && !node->n_x.v_subs[1])
- (void)obstack_1grow(&tmp_mem,(int)node->comp_value);
- /* Cheat */
- byte=node->sub_value;
- } else {
- f= &skip_funs[node->comp_value-SKIP];
- byte=node->comp_value;
- }
-
- #ifdef TEST
- if(!f)
- panic("f is zero in byte_compile!");
- #endif
- switch(GET_COMP(f->fn_comptype)) {
- case C_IF:
- /* if compiles to
- test-code IF amt-to-skip-on-false true-code SKIP
- amt-to-skip-on-true false-code */
- if(node->n_x.v_subs[0]) {
- if(node->n_x.v_subs[0]->n_x.v_subs[0]) {
- /* Put out the test-code */
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0]->n_x.v_subs[0];
- node->n_x.v_subs[0]->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- /* Put out IF, null-byte to backpatch */
- (void)obstack_1grow(&tmp_mem,byte);
- node->add_byte=obstack_object_size(&tmp_mem);
- (void)obstack_1grow(&tmp_mem,0);
-
- /* put out true-code */
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0]->n_x.v_subs[1];
- node->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- if(node->n_x.v_subs[1]) {
-
- (void)obstack_1grow(&tmp_mem,SKIP);
- (void)obstack_1grow(&tmp_mem,0);
- add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
- node->add_byte=obstack_object_size(&tmp_mem)-1;
-
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[1];
- node->n_x.v_subs[1]=0;
- node=new_node;
- goto loop;
- }
- add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
- break;
-
- case C_ANDOR:
- if(node->n_x.v_subs[0]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0];
- node->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- if(node->n_x.v_subs[1]) {
- (void)obstack_1grow(&tmp_mem,byte);
- node->add_byte=obstack_object_size(&tmp_mem);
- (void)obstack_1grow(&tmp_mem,0); /* for backpatching */
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[1];
- node->n_x.v_subs[1]=0;
- node=new_node;
- goto loop;
- }
- add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
- break;
-
- case C_ERR:
- (void)obstack_1grow(&tmp_mem,byte);
- node->add_byte=obstack_object_size(&tmp_mem);
- (void)obstack_1grow(&tmp_mem,0);
- (void)obstack_1grow(&tmp_mem,node->n_x.v_int);
- node->n_x.v_string=ename[node->n_x.v_int];
- push_stack(str_stack,node);
- break;
-
- case C_FLT:
- (void)obstack_1grow(&tmp_mem,byte);
- (void)obstack_grow(&tmp_mem,&(node->n_x.v_float),sizeof(double));
- break;
-
- case C_INT:
- (void)obstack_1grow(&tmp_mem,byte);
- (void)obstack_grow(&tmp_mem,&(node->n_x.v_int),sizeof(long));
- break;
-
- case C_STR:
- (void)obstack_1grow(&tmp_mem,byte);
- node->add_byte=obstack_object_size(&tmp_mem);
- (void)obstack_1grow(&tmp_mem,0);
- push_stack(str_stack,node);
- break;
-
- case C_VAR:
- add_ref_to(obstack_object_size(&tmp_mem));
- add_var_ref(node->n_x.v_var);
- (void)obstack_1grow(&tmp_mem,byte);
- (void)obstack_grow(&tmp_mem,&(node->n_x.v_var),sizeof(struct var *));
- break;
-
- case C_CELL:
- add_ref_to(obstack_object_size(&tmp_mem));
- add_ref(node->n_x.v_rng.lr,node->n_x.v_rng.lc);
- (void)obstack_1grow(&tmp_mem,byte);
- #if BITS_PER_CELLREF==16
- (void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lr>>8);
- (void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lr);
- (void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lc>>8);
- (void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lc);
- #else
- #if BITS_PER_CELLREF==8
- (void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lr);
- (void)obstack_1grow(&tmp_mem,node->n_x.v_rng.lc);
- #else
- Insert appropriate code here
- #endif
- #endif
- break;
-
- case C_RANGE:
- add_ref_to(obstack_object_size(&tmp_mem));
- add_range_ref(&(node->n_x.v_rng));
- (void)obstack_1grow(&tmp_mem,byte);
- (void)obstack_grow(&tmp_mem,&(node->n_x.v_rng),sizeof(struct rng));
- break;
-
- case C_FN0:
- case C_CONST:
- if(f->fn_comptype&C_T)
- add_timer_ref(obstack_object_size(&tmp_mem));
- (void)obstack_1grow(&tmp_mem,byte);
- break;
-
- case C_FN0X:
- add_ref_to(obstack_object_size(&tmp_mem));
- (void)obstack_1grow(&tmp_mem,byte);
- break;
-
- case C_FN1:
- case C_UNA:
- if(node->n_x.v_subs[0]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0];
- node->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- if(f->fn_comptype&C_T)
- add_timer_ref(obstack_object_size(&tmp_mem));
- (void)obstack_1grow(&tmp_mem,byte);
- break;
-
- case C_FN2:
- case C_INF:
- if(node->n_x.v_subs[0]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0];
- node->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- if(node->n_x.v_subs[1]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[1];
- node->n_x.v_subs[1]=0;
- node=new_node;
- goto loop;
- }
- (void)obstack_1grow(&tmp_mem,byte);
- break;
-
- case C_FN3:
- if(node->n_x.v_subs[0]) {
- if(node->n_x.v_subs[0]->n_x.v_subs[0]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0]->n_x.v_subs[0];
- node->n_x.v_subs[0]->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0]->n_x.v_subs[1];
- node->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- if(node->n_x.v_subs[1]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[1];
- node->n_x.v_subs[1]=0;
- node=new_node;
- goto loop;
- }
- if(f->fn_comptype&C_T)
- add_timer_ref(obstack_object_size(&tmp_mem));
- (void)obstack_1grow(&tmp_mem,byte);
- break;
-
- case C_FN4:
- if(node->n_x.v_subs[0]) {
- if(node->n_x.v_subs[0]->n_x.v_subs[0]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0]->n_x.v_subs[0];
- node->n_x.v_subs[0]->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[0]->n_x.v_subs[1];
- node->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- if(node->n_x.v_subs[1]) {
- if(node->n_x.v_subs[1]->n_x.v_subs[0]) {
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[1]->n_x.v_subs[0];
- node->n_x.v_subs[1]->n_x.v_subs[0]=0;
- node=new_node;
- goto loop;
- }
- push_stack(fn_stack,node);
- new_node=node->n_x.v_subs[1]->n_x.v_subs[1];
- node->n_x.v_subs[1]=0;
- node=new_node;
- goto loop;
- }
- if(f->fn_comptype&C_T)
- add_timer_ref(obstack_object_size(&tmp_mem));
- (void)obstack_1grow(&tmp_mem,byte);
- break;
-
- case C_FNN:
- if(node->n_x.v_subs[1]) {
- if(node->add_byte==0)
- for(new_node=node;new_node->n_x.v_subs[1];new_node=new_node->n_x.v_subs[1])
- node->add_byte++;
- for(new_node=node;new_node->n_x.v_subs[1]->n_x.v_subs[1];new_node=new_node->n_x.v_subs[1])
- ;
- push_stack(fn_stack,node);
- node=new_node->n_x.v_subs[1]->n_x.v_subs[0];
- new_node->n_x.v_subs[1]=0;
- goto loop;
- }
- (void)obstack_1grow(&tmp_mem,byte);
- (void)obstack_1grow(&tmp_mem,node->add_byte);
- break;
-
- default:
- panic("Bad comptype %d",f->fn_comptype);
- }
- node=(struct node *)pop_stack(fn_stack);
- if(node)
- goto loop;
-
- (void)obstack_1grow(&tmp_mem,0);
-
- while(node=pop_stack(str_stack)) {
- add_backpatch(node->add_byte,obstack_object_size(&tmp_mem));
- (void)obstack_grow(&tmp_mem,node->n_x.v_string,strlen(node->n_x.v_string)+1);
- }
-
- buf_siz=obstack_object_size(&tmp_mem);
- ret=(unsigned char *)ck_malloc(buf_siz);
- bcopy(obstack_finish(&tmp_mem),ret,buf_siz);
-
- need_relax=0;
- for(n=0;n<patches_used;n++) {
- long offset;
-
- offset=(patches[n].to-patches[n].from)-1;
- if(offset<0 || offset>255)
- need_relax++;
- else
- ret[patches[n].from]=offset;
- }
- if(need_relax) {
- int n_lo;
- long offset;
- int start;
- extern void sort();
-
- /* ... Sort the patches list ... */
- sort(patches_used,cmp_patch,swp_patch,rot_patch);
-
- while(need_relax) {
-
- ret=ck_realloc(ret,buf_siz+need_relax);
- for(n_lo=0;n_lo<patches_used;n_lo++) {
- offset=(patches[n_lo].to-patches[n_lo].from)-1;
- if(offset<0 || offset>255-need_relax)
- break;
- }
-
- /* n_lo points to the first jump that may need to be relaxed */
- for(n=n_lo;n<patches_used;n++) {
- offset=(patches[n].to-patches[n].from)-1;
- if(offset<0 || offset>255) {
- int nn;
-
- start=patches[n].from;
-
- ret[start-1]++;/* Translate insn to LONG */
- ret[start ]=offset;
- bcopy(&ret[start+1],&ret[start+2],buf_siz-start);
- ret[start+1]=offset>>8;
- need_relax--;
- buf_siz++;
- for(nn=0;nn<patches_used;nn++) {
- if(patches[nn].from>start)
- patches[nn].from++;
- if(patches[nn].to>start)
- patches[nn].to++;
- if(patches[nn].from<start && patches[nn].to>start && ret[patches[nn].from]++==255) {
- if(ret[patches[nn].from-1]&01)
- ret[patches[nn].from+1]++;
- else
- need_relax++;
- }
- }
- }
- }
- }
- }
-
- (void)obstack_free(&tmp_mem,tmp_mem_start);
-
- patches_used=0;
-
- return ret;
- }
-
- /* Back when strings stored a char*, they needed to be freed when a
- byte-compiled expression was freed. Now that they're appended to the end,
- they don't need to be specially freed anymore.
- */
- void
- byte_free FUN1(unsigned char *,form)
- {
- /* no longer needed
- unsigned char *f;
-
- for(f=form;*f;f++) {
- switch(*f) {
- case IF:
- case F_IF:
- case SKIP:
- case AND:
- case OR:
- case CONST_STR:
- f++;
- break;
- case CONST_INT:
- f+=sizeof(long);
- break;
- case CONST_FLT:
- f+=sizeof(double);
- break;
- case VAR:
- f+=sizeof(struct var *);
- break;
- case R_CELL:
- case R_CELL|ROWREL:
- case R_CELL|COLREL:
- case R_CELL|ROWREL|COLREL:
- f+=EXP_ADD;
- break;
- case RANGE:
- case RANGE|LRREL:
- case RANGE|LRREL|LCREL:
- case RANGE|LRREL|LCREL|HCREL:
- case RANGE|LRREL|HCREL:
- case RANGE|LRREL|HRREL:
- case RANGE|LRREL|HRREL|LCREL:
- case RANGE|LRREL|HRREL|LCREL|HCREL:
- case RANGE|LRREL|HRREL|HCREL:
- case RANGE|HRREL:
- case RANGE|HRREL|LCREL:
- case RANGE|HRREL|LCREL|HCREL:
- case RANGE|HRREL|HCREL:
- case RANGE|LCREL:
- case RANGE|LCREL|HCREL:
- case RANGE|HCREL:
- f+=EXP_ADD_RNG;
- break;
- case F_PRINTF:
- case F_CONCAT:
- case F_ONEOF:
- case F_STRSTR:
- case F_EDIT:
- case AREA_SUM:
- case AREA_PROD:
- case AREA_AVG:
- case AREA_STD:
- case AREA_MAX:
- case AREA_MIN:
- case AREA_CNT:
- case AREA_VAR:
- f++;
- break;
- default:
- break;
- }
- } */
- free(form);
- }
-
- /* This tries to tell if a byte-compiled expression is a constant. If it
- is a constant, we can free it, and never try to recompute its value.
- This returns non-zero if the expression is constant.*/
- int
- is_constant FUN1(unsigned char *,bytes)
- {
- /* It's constant, but it's already been dealt with.
- Pretend it isn't. */
- if(!bytes)
- return 0;
-
- switch(bytes[0]) {
- case CONST_ERR:
- return (bytes[3]==0 && !strcmp((char *)bytes+4,ename[bytes[2]]));
- case CONST_INT:
- return bytes[sizeof(long)+1]==ENDCOMP;
- case CONST_FLT:
- return bytes[sizeof(double)+1]==ENDCOMP;
- case CONST_STR:
- return bytes[2]==ENDCOMP;
- case F_TRUE:
- case F_FALSE:
- case CONST_INF:
- case CONST_NINF:
- case CONST_NAN:
- return bytes[1]==ENDCOMP;
- default:
- return 0;
- }
- }
-